﻿#pragma execution_character_set("utf-8")
#include <iostream>
#include <QPushButton>
#include <QApplication>
#include <QString>
#include <QMovie>
#include <QDir>
#include <QFileDialog>
#include <QMessageBox>
#include <vector>
#include "main_window_c.h"
#include "commons.h"
#include "detect_thread.h"

MainWindow::MainWindow()
{
    ui.setupUi(this);
    this->connect_slots();

    // init spinbox
    this->ui.iou_spinbox->setRange(0, 1);
    this->ui.iou_spinbox->setSingleStep(0.01);
    this->ui.iou_slider->setTracking(false);
    this->ui.conf_spinbox->setRange(0, 1);
    this->ui.conf_slider->setTracking(false);
    this->ui.conf_spinbox->setSingleStep(0.01);

    // init slider
    this->ui.iou_slider->setRange(0, 100);
    this->ui.iou_slider->setSingleStep(1);
    this->ui.conf_slider->setRange(0, 100);
    this->ui.conf_slider->setSingleStep(1);

	// 固定窗口大小
    this->setWindowTitle("detect system");
    this->setWindowIcon(QIcon(":/icon/HPU.png"));
    this->setFixedSize(this->width(), this->height());

	// 设置默认IOU和CONF
	this->reset_iou_slot();
	this->reset_conf_slot();
    
    
	this->refresh_model_list();   // 刷新下拉列表
	emit this->ui.model_select->activated(0);  // 加载第一个模型
    this->show();

}

MainWindow::~MainWindow()
{
}

void MainWindow::show_img(QString& path) {
    if (!QFile::exists(path)) {
        QMessageBox::warning(this, "Error", path + "图片不存在");
    }
    QPixmap pixmap(path);
    this->show_img(pixmap);
    //ui.show_detect->setPixmap(pixmap.scaled(ui.show_detect->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}

void MainWindow::show_img(QPixmap& pixmap)
{
    if (pixmap.isNull()) {
        QMessageBox::warning(this, "Error", "Failed to load image");
        return;
    }
    int width = ui.show_detect->width();
    int height = ui.show_detect->height();
    float rate = 0.8f;
    ui.show_detect->setAlignment(Qt::AlignCenter);
    ui.show_detect->setPixmap(pixmap.scaled(int(width * rate), int(height * rate), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}

void MainWindow::show_img(QPixmap&& pixmap) {
    this->show_img(pixmap);
}

bool prepare_thread(int thread_id) {
    if (DetectThreadBase::ID == thread_id) {
		// 重复相同类型的检测，不做处理
        return true;
    }
    else if (DetectThreadBase::ID != 0) {
        // 存在一种类型正在检测
        DetectThreadBase::stop();
    }
    return false;
}
// slots
void MainWindow::cammera_slot()
{
    if (prepare_thread(CameraDetectThread::ID)) {
        return;
    }
    if (!this->check_model()) {  // 模型检测未通过
        return;
    }
    CameraDetectThread* dt = new CameraDetectThread(*this);
    dt->start();
}

void MainWindow::image_slot()
{
    if (prepare_thread(ImageDetectThread::ID)) {
        return;
    }
    if (!this->check_model()) {  // 模型检测未通过
        return;
    }
    // 选择图片文件
    QString file = QFileDialog::getOpenFileName(this, "Open File", ".", "Images(*.png *.jpg)");
    if (file == "") {
        return;
    }
    // 检测
    ImageDetectThread* dt = new ImageDetectThread(*this, file);
    dt->start();
}

void MainWindow::video_slot()
{
    if (prepare_thread(VideoDetectThread::ID)) {
        return;
    }
    if (!this->check_model()) {  // 模型检测未通过
        return;
    }
    QString file = QFileDialog::getOpenFileName(this, "Open File", ".", "Videos(*.mp4)");
    if (file == "") {
        return;
    }
    VideoDetectThread* dt = new VideoDetectThread(*this, file);
    dt->start();
}

void MainWindow::iou_spinbox_slot(double value)
{
    this->ui.iou_slider->blockSignals(true);
    this->ui.iou_slider->setValue(int(value*100));
    this->ui.iou_slider->blockSignals(false);
}

void MainWindow::conf_spinbox_slot(double value)
{
    this->ui.conf_slider->blockSignals(true);
    this->ui.conf_slider->setValue(int(value * 100));
    this->ui.conf_slider->blockSignals(false);

}

void MainWindow::iou_slider_slot(int value) {
    this->ui.iou_spinbox->blockSignals(true);
    this->ui.iou_spinbox->setValue(value * 1.0 / 100);
    this->ui.iou_spinbox->blockSignals(false);
}

void MainWindow::conf_slider_slot(int value) {
    this->ui.conf_spinbox->blockSignals(true);
    this->ui.conf_spinbox->setValue(value * 1.0 / 100);
    this->ui.conf_spinbox->blockSignals(false);
}

void MainWindow::reset_iou_slot()
{
    this->iou_slider_slot(50);
    this->iou_spinbox_slot(0.5);
}

void MainWindow::reset_conf_slot()
{
    this->conf_slider_slot(45);
    this->conf_spinbox_slot(0.45);
}

void MainWindow::model_select_slot(int index)
{
    if (index == this->current_weight_index or this->ui.model_select->count() == 0) {
		return;
    }
	this->current_weight_index = index;
    QString file = this->ui.model_select->itemText(index);

	float iou = this->ui.iou_spinbox->value();
	float conf = this->ui.conf_spinbox->value();
    // 加载模型

    this->global_threading.reset(new WarmUpThread(*this, "weights/" + file, iou, conf, cv::Size(640, 640)));
    this->global_threading->start();
}

void MainWindow::import_model_button_slot()
{
	QString file = QFileDialog::getOpenFileName(this, "Open File", ".", "Models(*.onnx *.txt)");
	if (file == "") {
		return;
	}
	bool copy_success = commons::copy_weights(file, "weights");
    if (copy_success) {
        this->refresh_model_list();
        this->append_log("导入成功");
		// 如果是 onnx 文件, 选中导入的模型

        if (file.endsWith(".onnx")) {
            std::string file_name = commons::get_file_name(file.toStdString());;
			int index = this->ui.model_select->findText(QString::fromStdString(file_name));
			if (index != -1) {
				this->current_weight_index = -1; // 重新加载模型
				emit this->ui.model_select->activated(index);
			}
        }
    }
}

void MainWindow::start_loading_movie_slot()
{
    if (this->movie == nullptr) {
        this->movie.reset(new QMovie(":/gif/loading.gif"));
        QRect rect = this->ui.show_detect->geometry();
        int bw = rect.width();
        int bh = rect.height();
        double scale = std::min(bw, bh) * 0.4;
        this->movie->setScaledSize(QSize(scale, scale));
    }

    if (this->ui.show_detect->movie() == nullptr) {
		this->ui.show_detect->setMovie(this->movie.get());
		this->ui.show_detect->setAlignment(Qt::AlignCenter);
    }
    auto m = this->ui.show_detect->movie();
    if (m != nullptr) {
        m->start();
    }
    this->disable_all_button();
}

void MainWindow::stop_loading_movie_slot()
{
	if (this->ui.show_detect->movie() != nullptr) {
		this->ui.show_detect->movie()->stop();
        this->ui.show_detect->clear();
	}
	this->enable_all_button();
}

void MainWindow::islabel_slot(bool value)
{
    this->ui.islabel->setChecked(value);
}

void MainWindow::connect_slots()
{
    QObject::connect(ui.cammera_button, SIGNAL(clicked()), this, SLOT(cammera_slot()));
    QObject::connect(ui.image_button, SIGNAL(clicked()), this, SLOT(image_slot()));
    QObject::connect(ui.video_button, SIGNAL(clicked()), this, SLOT(video_slot()));

    QObject::connect(ui.iou_spinbox, SIGNAL(valueChanged(double)), this, SLOT(iou_spinbox_slot(double)));
    QObject::connect(ui.conf_spinbox, SIGNAL(valueChanged(double)), this, SLOT(conf_spinbox_slot(double)));

    QObject::connect(ui.iou_slider, SIGNAL(valueChanged(int)), this, SLOT(iou_slider_slot(int)));
    QObject::connect(ui.conf_slider, SIGNAL(valueChanged(int)), this, SLOT(conf_slider_slot(int)));

    QObject::connect(ui.reset_iou_button, SIGNAL(clicked()), this, SLOT(reset_iou_slot()));
    QObject::connect(ui.reset_conf_button, SIGNAL(clicked()), this, SLOT(reset_conf_slot()));
	QObject::connect(ui.model_select, SIGNAL(activated(int)), this, SLOT(model_select_slot(int)));
	QObject::connect(ui.import_model_button, SIGNAL(clicked()), this, SLOT(import_model_button_slot()));
    
	QObject::connect(this, SIGNAL(start_loading_movie_signal()), this, SLOT(start_loading_movie_slot()));
	QObject::connect(this, SIGNAL(stop_loading_movie_signal()), this, SLOT(stop_loading_movie_slot()));
}

void MainWindow::refresh_model_list()
{
	QDir dir("weights");
	QStringList filters;
	filters << "*.onnx";
	QStringList files = dir.entryList(filters);
	ui.model_select->clear();
	ui.model_select->addItems(files);
}

void MainWindow::disable_all_button()
{
	this->ui.cammera_button->setDisabled(true);
	this->ui.image_button->setDisabled(true);
	this->ui.video_button->setDisabled(true);
	this->ui.model_select->setDisabled(true);
	this->ui.import_model_button->setDisabled(true);

}

void MainWindow::enable_all_button()
{
	this->ui.cammera_button->setDisabled(false);
	this->ui.image_button->setDisabled(false);
	this->ui.video_button->setDisabled(false);
	this->ui.model_select->setDisabled(false);
	this->ui.import_model_button->setDisabled(false);
}

bool MainWindow::check_model()
{
    // 模型不存在
    if (this->inference == nullptr and this->ui.model_select->count() == 0) {
        QMessageBox::warning(this, "Error", QString("未检测到模型"));
        return false;
    }


	// 模型存在,检测txt文件
    std::string base_name = commons::get_base_name(this->ui.model_select->currentText().toStdString());
    std::string txt_name = base_name + ".txt";
    std::string txt_path = "weights/" + txt_name;
    if (!QFile::exists(QString::fromStdString(txt_path))) {
        QString msg;
        msg = msg + "未检测到" + txt_name.c_str() + ", 请导入...";
        QMessageBox::warning(this, "Error", QString::fromStdString(txt_name) + "不存在");
        return false;
    }
    if (this->inference != nullptr) {
        this->inference->loadClassesFromFile();
    }
    return true;
}

void MainWindow::load_model_from_model_list()
{
	int index = this->ui.model_select->currentIndex();
	this->model_select_slot(index);
}

void MainWindow::closeEvent(QCloseEvent* event)
{
	if (this->global_threading != nullptr) {
		DetectThreadBase* dt = dynamic_cast<DetectThreadBase*>(this->global_threading.get());
		if (dt != nullptr) {
			dt->stop();
            dt->wait();
		}
	}
}

void MainWindow::append_log(QString text)
{
    ui.output->append(text);
}
